//-----------------------------------------------
//  Copyright (c) 2007 Microsoft
//  Exchange Web Services Gadget
// ----------------------------------------------

// Formats a FindItem request ready to be sent to EWS, using the provided distinguished folder Id and view.
function formatFindItemRequest(distinguishedFolderId, view)
{
    var data = "";
    
    data += "<?xml version='1.0' encoding='utf-8'?>";
    data += "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'";
    data += "  xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'>";
    data += "  <soap:Body>";
    data += "    <FindItem xmlns='http://schemas.microsoft.com/exchange/services/2006/messages'";
    data += "      xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'";
    data += "      Traversal='Shallow'>";
    data += "      <ItemShape>";
    data += "        <t:BaseShape>IdOnly</t:BaseShape>";
    data += "        <t:AdditionalProperties>";
    data += "          <t:FieldURI FieldURI='message:From'/>";
    data += "          <t:FieldURI FieldURI='item:Subject'/>";
    data += "          <t:FieldURI FieldURI='message:IsRead'/>";
    data += "          <t:FieldURI FieldURI='item:DateTimeReceived'/>";
	data += "          <t:FieldURI FieldURI='calendar:Start'/>";
	data += "          <t:FieldURI FieldURI='calendar:End'/>";
	data += "          <t:FieldURI FieldURI='calendar:Location'/>";
    data += "          <t:FieldURI FieldURI='task:Status'/>";
    data += "          <t:FieldURI FieldURI='task:DueDate'/>";
    data += "        </t:AdditionalProperties>";
    data += "      </ItemShape>";
    data +=			view;
    data += "      <ParentFolderIds>";
    data += "        <t:DistinguishedFolderId Id='" + distinguishedFolderId + "'/>";
    data += "      </ParentFolderIds>";
    data += "    </FindItem>";
    data += "  </soap:Body>";
    data += "</soap:Envelope>";
    
    return data;
}

// Formats an IndexedPageItemView element that can be used in a FindItem request given the offset and maxEntriesReturned parameters.
function formatIndexedPageView(offset, maxEntriesReturned)
{
    return "<IndexedPageItemView Offset='" + offset + "' MaxEntriesReturned='" + maxEntriesReturned + "' BasePoint='Beginning'/>";
}

// Sends a FindItem request to EWS to retrieve e-mails in the inbox folder.
function getMessages()
{
    var data = formatFindItemRequest(
        "inbox", 
        formatIndexedPageView(
            currentPage * getVisibleTileCount(),
            getVisibleTileCount()));
    
    executeEwsRequest(data, readMessages);
	getUnreadMailCount();
}

// Reads the response to the FindItem request sent in getMessages
function readMessages(responseString)
{
    readItems(responseString);
}

// Sends a FindItem request to EWS to retrieve tasks in the tasks folder.
function getTasks()
{
    var data = formatFindItemRequest(
        "tasks", 
        formatIndexedPageView(
            currentPage * getVisibleTileCount(),
            getVisibleTileCount()));
            
    executeEwsRequest(data, readTasks);
}

// Sends a FindItem request to EWS to retrieve tasks in the tasks folder.
function getCalendarItems()
{
    // Retrieve appointments and meetings for the next 24 hours.
    var now = new Date();
    var startDate = convertDateToXsDateTimeString(now);
    
    now.setDate(now.getDate() + 7);
    var endDate = convertDateToXsDateTimeString(now);
    
    var data = formatFindItemRequest(
        "calendar", 
		"<CalendarView StartDate='" + startDate + "' EndDate= '" + endDate + "' MaxEntriesReturned= '" + getVisibleTileCount() + "'/>");
	
    executeEwsRequest(data, readCalendarItems);
}

// Returns the CSS class for item tiles given the gadget's current docking state.
function getTileClass()
{
	return "undockedTile";
}

// Returns the CSS class for paging controls area given the gadget's current docking state.
function getPagingControlsAreaClass()
{
	return "undockedPagingContainer";
}

// Navigate to the previous item page if possible.
function previousPage()
{
    if (currentPage > 0)
    {
        currentPage--;
        resetState();
        refreshTiles();
    }
}

// Navigate to the next item page.
function nextPage()
{
    currentPage++;
    resetState();
    refreshTiles();
}

// Generates the HTML for the item tiles.
function renderItems(findResults)
{
    var html = "";
     
    for (i = 0 ; i < findResults.nodes.length; i++) 
    {
        currentNode = findResults.nodes[i];
        
        var isReadNode = currentNode.getElementsByTagName("IsRead")[0];
        var isRead = true;
        
        if (isReadNode != null)
        {
            isRead = isReadNode.textContent == "true";
        }
        
        var line1 = "";
        var line2 = "";
        var line3 = "";
        var line1TextClass = "tileText";
        
        switch (currentNode.nodeName)
        {
            case "t:Message":
            case "t:MeetingMessage":
            case "t:MeetingResponse":
            case "t:MeetingCancellation":
                line1 =	getXmlNodeText(currentNode, "From");
                line2 = getXmlNodeText(currentNode, "Subject");
                line3 = formatDateTime(
                    convertXsDateTimeToDate(getXmlNodeText(currentNode, "DateTimeReceived")),
                    true,
                    true);
                
                if (!isRead)
                {
                    line1TextClass = "tileTextBold";
                }
                
                break;
            case "t:Task":
                line1 = getXmlNodeText(currentNode, "Subject");
                line2 = getTaskStatusDescription(getXmlNodeText(currentNode, "Status"));
                
                var dueDate = convertXsDateTimeToDate(getXmlNodeText(currentNode, "DueDate"));
                var now = new Date();
                
                if (dueDate < now)
                {
                    line1TextClass = "tileTextRed";
                }
                
                line3 = "Due " + formatDateTime(dueDate, false, false);
                
                break;
            case "t:CalendarItem":
            case "t:MeetingRequest":
                line1 = getXmlNodeText(currentNode, "Subject");
                
                var startDate = convertXsDateTimeToDate(getXmlNodeText(currentNode, "Start"));
                var endDate = convertXsDateTimeToDate(getXmlNodeText(currentNode, "End"));
                var now = new Date();
                
                line2 = formatShortCalendarItemDate(startDate, now) + " - " + formatShortCalendarItemDate(endDate, startDate);
                line3 = getXmlNodeText(currentNode, "Location");
                
                line1TextClass = "tileTextBold";
                
                break;
            default:
                line1 = currentNode.text;
                break;
        }
    
        var id = currentNode.getElementsByTagName("ItemId")[0].getAttribute("Id");
        var changeKey = currentNode.getElementsByTagName("ItemId")[0].getAttribute("ChangeKey");

        html += '<div class="' + getTileClass() + '" onclick="openFlyout(' + "'" + id + "'" + ')">';
        html += '  <span class="tileTextZone">';
        html += '    <div class="' + line1TextClass + '">' + line1 + '</div>';
        html += '    <div class="tileText">' + line2 + '</div>';
        html += '    <div class="tileTextSmall">' + line3 + '</div>';
        html += '  </span>';
        html += '</div>';
    }    
    
    return html;
}

// Renders the paging controls are.
function renderPagingControls(findResults)
{
    var html = "";
    
    if (findResults.totalItems > getVisibleTileCount())
    {
        html += '<table class="' + getPagingControlsAreaClass() + '" cellspacing=0 cellpadding=0 style="table-layout: fixed; font-size: 1px; width: 100%; height: 15px; padding-left: 2px; padding-right: 2px;">';
        html += '  <tr>';
        
        if (currentPage > 0)
        {
            html += '    <td style="width: 15%; height: 100%; cursor: pointer" onclick="previousPage();">';
            html += '      <img align="left" src="images/PreviousPage.png"/>';
        }
        else
        {
            html += '    <td style="width: 15%; height: 100%;">';
        }
        
        html += '    </td>';
        html += '    <td class="pagingControlsAreaText" align="center">page ' + (currentPage + 1) + '</td>';
        
        if ((currentPage * getVisibleTileCount() + findResults.nodes.length) < findResults.totalItems)
        {
            html += '    <td style="width: 15%; height: 100%; cursor: pointer" onclick="nextPage();">';
            html += '      <img align="right" src="images/NextPage.png"/>';
        }
        else
        {
            html += '    <td style="width: 15%; height: 100%;">';
        }
        
        html += '    </td>';
        html += '  </tr>';
        html += '</table>';
    }
    
    return html;
}

// Renders the summary zone of the calendar view.
function renderCalendarSummary(findResults)
{
    var html = "";
   
/*	 
    html += '<table class="' + getPagingControlsAreaClass() + '" cellspacing=0 cellpadding=0 style="table-layout: fixed; width: 100%; padding-left: 2px; padding-right: 2px;">';
    html += '  <tr>';
    html += '    <td class="pagingControlsAreaText" align="center">';
    
    var additionalEventCount = findResults.totalItems - findResults.nodes.length;
    
    if (additionalEventCount > 0)
    {
        html += additionalEventCount;
        
        if (additionalEventCount > 1)
        {
            html += " more events";
        }
        else
        {
            html += " more event";
        }
    }
    else
    {
        html += "No other events";
    }
    
    html += '    </td>';
    html += '  </tr>';
    html += '</table>';
*/

    html += '<table class="' + getPagingControlsAreaClass() + '" cellspacing=0 cellpadding=0 style="table-layout: fixed; font-size: 1px; width: 100%; height: 15px; padding-left: 2px; padding-right: 2px;">';
    html += '  <tr>';    
	html += '    <td class="pagingControlsAreaText" align="center">';
    
    var additionalEventCount = findResults.totalItems - findResults.nodes.length;
    
    if (additionalEventCount > 0)
    {
        html += additionalEventCount;
        
        if (additionalEventCount > 1)
        {
            html += " more events";
        }
        else
        {
            html += " more event";
        }
    }
    else
    {
        html += "No other events";
    }
    
    html += '    </td>';
    html += '  </tr>';
    html += '</table>';

    return html;
}

// Represents a "class" encapsulating FindItem results.
function findItemResults(nodes, totalItems)
{
    this.nodes = nodes;
    this.totalItems = totalItems;
}

// Extracts the item nodes (the nodes under the t:Items node) from a FindItem response.
function extractItemNodes(xmlDoc)
{
    var totalItems = xmlDoc.getElementsByTagName("RootFolder")[0].getAttribute("TotalItemsInView");
    var nodes = null;
    
    var itemsElements = xmlDoc.getElementsByTagName("Items");
    
    if (itemsElements != null && itemsElements.length > 0)
    {
        if (itemsElements[0].childNodes.length > 0)
        {
            nodes = itemsElements[0].childNodes;
        }
    }
    
    return new findItemResults(nodes, totalItems);
}

// Extracts the item nodes (the nodes under the t:Items node) from a FindItem response.
function extractSingleItemNodes(xmlDoc)
{
    var nodes = null;    
    var itemsElements = xmlDoc.getElementsByTagName("Items");
    
    if (itemsElements != null && itemsElements.length > 0)
    {
        if (itemsElements[0].childNodes.length > 0)
        {
            nodes = itemsElements[0].childNodes;
        }
    }
    
    return new findItemResults(nodes, itemsElements.length);
}


function createXmlDocument(responseText)
{
	var parser = new DOMParser();
	var xmlDoc = parser.parseFromString(responseText, "text/xml");
	
	return xmlDoc;
}

// Reads the response to a FindItem EWS request and renders the items that it contains.
function readItems(responseString)
{
	var xmlDoc = createXmlDocument(responseString);
	
	var findResults = extractItemNodes(xmlDoc);
	
	if (findResults.nodes != null)
	{
		var html = renderItems(findResults);
		html += renderPagingControls(findResults);

		tileContainer.innerHTML = html;    
	}
	else
	{
		setMessage("There are no items to show in this folder at this time.");
	}
	
	findResults = null;
	xmlDoc = null;
}

// Reads the response to a FindItem EWS request and renders the items that it contains.
function readTasks(responseString)
{
    readItems(responseString);
    startTimer();
}

// Reads the response to a FindItem EWS request and renders the items that it contains.
function readCalendarItems(responseString)
{
	var xmlDoc = createXmlDocument(responseString);
	
	var findResults = extractItemNodes(xmlDoc);
	
	if (findResults.nodes != null)
	{
		var html = renderItems(findResults);
		html += renderCalendarSummary(findResults);

		tileContainer.innerHTML = html;    
	}
	else
	{
		setMessage("There are no items to show in this folder at this time.");
	}
	
	findResults = null;
	xmlDoc = null;
    
    startTimer();
}

// Send a GetFolder EWS request to retrieve the number of unread messages in the inbox.
function getUnreadMailCount()
{
    // Create the SOAP message
    var data = "";
    data += "<?xml version='1.0' encoding='utf-8'?>";
    data += "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'";
    data += "  xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'>";
    data += "  <soap:Body>";
    data += "    <GetFolder xmlns='http://schemas.microsoft.com/exchange/services/2006/messages'";
    data += "      xmlns:t='http://schemas.microsoft.com/exchange/services/2006/types'>";
    data += "      <FolderShape>";
    data += "        <t:BaseShape>Default</t:BaseShape>";
    data += "      </FolderShape>";
    data += "      <FolderIds>";
    data += "        <t:DistinguishedFolderId Id='inbox'/>";
    data += "      </FolderIds>";
    data += "    </GetFolder>";
    data += "  </soap:Body>";
    data += "</soap:Envelope>";
    
    executeEwsRequest(data, readGetUnreadMailCountResponse);
}

// Reads the response to the GetFolder request sent in getUnreadMailCount.
function readGetUnreadMailCountResponse(responseString)
{
	if (getFolderToDisplay() == "Inbox")
	{
		var xmlDoc = createXmlDocument(responseString);
		var headerText = getFolderToDisplay();

		var unreadCountNodes = xmlDoc.getElementsByTagName("UnreadCount");
		
		if (unreadCountNodes != null && unreadCountNodes.length > 0)
		{
			var unreadCount = unreadCountNodes[0].textContent;
			
			if (unreadCount > 0)
			{
				headerText += " (" + unreadCount + " unread)";
			}
		}
		
		unreadCountNodes = null;
		xmlDoc = null;

		updateGadgetHeader(headerText);
	}
	
	startTimer();
}